/*
# pymoz, Python extension for the Mozilla Toolkit
# Copyright (C) 2012 Malek Hadj-Ali
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#include "pyWrappers.h"


/*******************************************************************************
 strings mgt
*******************************************************************************/

PyObject *
JSString_Decode(JSContext *cx, JSString *string)
{
    size_t size;
    const jschar *chars = JS_GetStringCharsAndLength(cx, string, &size);
    if (!chars) {
       return NULL;
    }
    return PyUnicode_DecodeUTF16((const char *)chars, size * 2, NULL, NULL);
}


static JSString *
PyBytes_AsJSString(JSContext *cx, PyObject *pybytes)
{
    JSString *string = NULL;
    char *chars = NULL;
    Py_ssize_t size;
    if (!PyBytes_AsStringAndSize(pybytes, &chars, &size)) {
        string = JS_NewStringCopyN(cx, chars, size);
    }
    return string;
}


static JSString *
PyUnicode_AsJSString(JSContext *cx, PyObject *pyunicode)
{
    JSString *string = NULL;
    PyObject *pytmp = PyUnicode_AsUTF16String(pyunicode);
    if (pytmp) {
        char *chars = NULL;
        Py_ssize_t size;
        if (!PyBytes_AsStringAndSize(pytmp, &chars, &size)) {
            string = JS_NewUCStringCopyN(cx, (jschar *)(chars + 2), (size / 2) - 1);
        }
        Py_DECREF(pytmp);
    }
    return string;
}


/*******************************************************************************
 conversion utils
*******************************************************************************/

PyObject *
PyObject_FromJSVal(JSContext *cx, jsval value)
{
    if (JSVAL_IS_PRIMITIVE(value)) {
        if (JSVAL_IS_VOID(value)) {
            if (!PyErr_Occurred()) {
                PyErr_SetString(PyExc_TypeError, "cannot convert 'undefined'");
            }
            return NULL;
        }
        if (JSVAL_IS_NULL(value)) {
            Py_RETURN_NONE;
        }
        if (JSVAL_IS_BOOLEAN(value)) {
            if (JSVAL_TO_BOOLEAN(value)) {
                Py_RETURN_TRUE;
            }
            Py_RETURN_FALSE;
        }
        if (JSVAL_IS_INT(value)) {
            return PyLong_FromLong(JSVAL_TO_INT(value));
        }
        if (JSVAL_IS_DOUBLE(value)) {
            return PyFloat_FromDouble(JSVAL_TO_DOUBLE(value));
        }
        if (JSVAL_IS_STRING(value)) {
            return JSString_Decode(cx, JSVAL_TO_STRING(value));
        }
        PyErr_SetString(PyExc_TypeError, "Unknown jsval primitive type");
        return NULL;
    }
    return PyJSObject_NewOrUsed(cx, JSVAL_TO_OBJECT(value));
}


jsval
PyObject_AsJSVal(JSContext *cx, PyObject *pyobj)
{
    if (pyobj == Py_None) {
        return JSVAL_NULL;
    }
    if (PyBool_Check(pyobj)) {
        if (pyobj == Py_True) {
            return JSVAL_TRUE;
        }
        return JSVAL_FALSE;
    }
    if (PyLong_Check(pyobj)) {
        long long_value = PyLong_AsLong(pyobj);
        if (long_value == -1 && PyErr_Occurred()) {
            return JSVAL_VOID;
        }
        return JS_NumberValue(long_value);
    }
    if (PyFloat_Check(pyobj)) {
        double double_value = PyFloat_AS_DOUBLE(pyobj);
        if (double_value == -1 && PyErr_Occurred()) {
            return JSVAL_VOID;
        }
        return JS_NumberValue(double_value);
    }
    if (PyBytes_Check(pyobj)) {
        JSString *string = PyBytes_AsJSString(cx, pyobj);
        if (!string) {
            return JSVAL_VOID;
        }
        return STRING_TO_JSVAL(string);
    }
    if (PyUnicode_Check(pyobj)) {
        JSString *string = PyUnicode_AsJSString(cx, pyobj);
        if (!string) {
            return JSVAL_VOID;
        }
        return STRING_TO_JSVAL(string);
    }
    JSObject *jsobj = JSPyObject_NewOrUsed(cx, pyobj);
    if (!jsobj) {
        return JSVAL_VOID;
    }
    return OBJECT_TO_JSVAL(jsobj);
}
